package com.hcloud.auth.api.config;

import com.hcloud.auth.api.handler.HcloudAccessDeniedHandler;
import com.hcloud.auth.api.handler.HcloudResourceAuthExceptionEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.client.RestTemplate;

/**
 * 资源服务器配置的基类，大部分内容都已经自动配置
 * 子类需要重写getResourceId方法定义自己的资源服务器标识
 * 子类需要重写configuer方法定义url拦截规则
 *
 * @Auther hepangui
 * @Date 2018/11/9
 */

public abstract class AbstractOAuth2ResourceServceConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    protected HcloudResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint;
    @Autowired
    protected HcloudAccessDeniedHandler accessDeniedHandler;
//    @Autowired
//    protected UserDetailsService userDetailsService;
    @Autowired
    protected TokenStore tokenStore;

    protected abstract String getResourceId();

    /**
     * 默认的配置，对外暴露
     *
     * @param http
     * @throws Exception
     */
    @Override
    public abstract void configure(HttpSecurity http) throws Exception;

    /**
     * //resourceId 用于分配给可授予的clientId
     * //stateless  标记以指示在这些资源上仅允许基于令牌的身份验证
     * //tokenStore token的存储方式（上一章节提到）
     * //accessDeniedHandler          权失败且主叫方已要求特定的内容类型响应
     * //resourceTokenServices        加载 OAuth2Authentication 和 OAuth2AccessToken 的接口
     * //eventPublisher            事件发布-订阅  根据异常的clazz触发不同event
     * //authenticationEntryPoint  认证异常流程处理返回
     * //tokenExtractor            token获取方式,默认BearerTokenExtractor
     * //                         从header获取token为空则从request.getParameter("access_token")
     *
     * @param config
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        var tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore);
        config.resourceId(getResourceId()).stateless(true)
                .tokenServices(tokenServices)
                .tokenStore(tokenStore)
                .authenticationEntryPoint(resourceAuthExceptionEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);
    }

    @Bean
    @LoadBalanced
    public RestTemplate lbRestTemplate() {
        return new RestTemplate();
    }




}
